import logging
from django.core.exceptions import ObjectDoesNotExist
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.authentication import TokenAuthentication
from rest_framework.parsers import JSONParser
from rest_framework.views import APIView
from api_test.common.api_response import JsonResponse
from api_test.common.common import record_dynamic
from api_test.models import Project, ApiDataType, ApiDataStructure
from api_test.serializers import ApiDataTypeSerializer, \
    ApiDataTypeDeserializer, ApiDataStructureSerializer, ApiDataStructureDeserializer, ProjectListSerializer

logger = logging.getLogger(__name__)  # 这里使用 __name__ 动态搜索定义的 logger 配置，这里有一个层次关系的知识点。


class DataType(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @swagger_auto_schema(manual_parameters=[
        openapi.Parameter(name="project_id", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER, description="项目id"),
        openapi.Parameter(name="type", in_=openapi.IN_QUERY, type=openapi.TYPE_STRING, description="数据类型"),
    ])
    def get(self, request):
        """
        获取数据类型
        """
        project_id = request.GET.get("project_id")
        type = request.GET.get("type")
        # 校验参数
        if not project_id:
            return JsonResponse(code="999996", msg="参数有误!")
        if not project_id.isdecimal():
            return JsonResponse(code="999996", msg="参数有误!")
        # 验证项目是否存在
        try:
            pro_data = Project.objects.get(id=project_id)
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在!")
        # 序列化结果
        pro_data = ProjectListSerializer(pro_data)
        # 校验项目状态
        if not pro_data.data["status"]:
            return JsonResponse(code="999985", msg="该项目已禁用")
        # 查找项目下所有接口状态码信息，并按id排序，序列化结果
        obi = ApiDataType.objects.filter(project=project_id, status=True)
        if type:
            obi = obi.filter(type=type)
        obi.order_by("id")
        serialize = ApiDataTypeSerializer(obi, many=True)
        return JsonResponse(data=serialize.data, code="999999", msg="成功!")


class AddDataType(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    def parameter_check(self, data):
        """
        校验参数
        """
        try:
            # 必传参数
            if not data.get("type") or not data.get("project_id"):
                return JsonResponse(code="999996", msg="参数有误!")
            # 校验project_id类型为int
            if not isinstance(data["project_id"], int):
                return JsonResponse(code="999996", msg="参数有误!")
        except KeyError:
            return JsonResponse(code="999996", msg="参数有误!")

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['project_id', 'type'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'complex': openapi.Schema(type=openapi.TYPE_INTEGER, description="是否复杂结构"),
            'type': openapi.Schema(type=openapi.TYPE_STRING, description="数据类型"),
            'description': openapi.Schema(type=openapi.TYPE_STRING, description="类型描述")
        },
    ))
    def post(self, request):
        """
        新增数据类型
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        # 校验项目状态
        try:
            obj = Project.objects.get(id=data["project_id"])
            if not request.user.is_superuser and obj.user.is_superuser:
                return JsonResponse(code="999983", msg="无操作权限！")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在!")
        pro_data = ProjectListSerializer(obj)
        if not pro_data.data["status"]:
            return JsonResponse(code="999985", msg="该项目已禁用")
        count = ApiDataType.objects.filter(type=data["type"], project=data["project_id"]).count()
        if count > 0:
            return JsonResponse(code="999997", msg="存在相同名称！")
        else:
            # 反序列化
            serializer = ApiDataTypeDeserializer(data=data)
            # 校验反序列化正确，正确则保存，外键为project
            if serializer.is_valid():
                serializer.save(project=obj)  # 如果去掉project=obj会报错"project_id"cannot be null
            else:
                return JsonResponse(code="999998", msg="失败!")
            # 新增操作
            record_dynamic(project=serializer.data.get("project_id"),
                           _type="添加", operationObject="数据类型", user=request.user.pk,
                           data="新增数据类型“%s”" % data["type"])
            return JsonResponse(data={
                "type_id": serializer.data.get("id")
            }, code="999999", msg="成功!")


class UpdateDataType(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    def parameter_check(self, data):
        """
        校验参数
        """
        try:
            # 必传参数
            if not data.get("type") or not data.get("project_id") or not data.get("id"):
                return JsonResponse(code="999996", msg="参数有误!")
            # 校验project_id, id类型为int
            if not isinstance(data["project_id"], int) or not isinstance(data["id"], int):
                return JsonResponse(code="999996", msg="参数有误!")
        except KeyError:
            return JsonResponse(code="999996", msg="参数有误!")

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['id', 'project_id', 'type'],
        properties={
            'id': openapi.Schema(type=openapi.TYPE_INTEGER, description="数据类型id"),
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'complex': openapi.Schema(type=openapi.TYPE_INTEGER, description="是否复杂结构"),
            'type': openapi.Schema(type=openapi.TYPE_STRING, description="数据类型"),
            'description': openapi.Schema(type=openapi.TYPE_STRING, description="类型描述")
        },
    ))
    def post(self, request):
        """
        修改数据类型
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        try:
            pro_data = Project.objects.get(id=data["project_id"])
            if not request.user.is_superuser and pro_data.user.is_superuser:
                return JsonResponse(code="999983", msg="无操作权限！")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在!")
        pro_data = ProjectListSerializer(pro_data)
        if not pro_data.data["status"]:
            return JsonResponse(code="999985", msg="该项目已禁用")
        try:
            obj = ApiDataType.objects.get(id=data["id"], project=data["project_id"])
        except ObjectDoesNotExist:
            return JsonResponse(code="999991", msg="id不存在!")
        serializer = ApiDataTypeDeserializer(data=data)
        if serializer.is_valid():
            serializer.update(instance=obj, validated_data=data)
        else:
            return JsonResponse(code="999998", msg="失败!")
        record_dynamic(project=serializer.data.get("project_id"),
                       _type="修改", operationObject="数据类型", user=request.user.pk,
                       data="修改数据类型码“%s”" % data["type"])
        return JsonResponse(code="999999", msg="成功!")


class DelDataType(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    def parameter_check(self, data):
        """
        校验参数
        """
        try:
            if not data.get("project_id") or not data.get("ids"):
                return JsonResponse(code="999996", msg="参数有误!")
            # 校验project_id, id类型为int
            if not isinstance(data["ids"], list) or not isinstance(data["project_id"], int):
                for i in data["ids"]:
                    if not isinstance(i, int) or not isinstance(int(i), int):
                        return JsonResponse(code="999995", msg="参数有误！")
                return JsonResponse(code="999995", msg="参数有误！")
        except KeyError:
            return JsonResponse(code="999996", msg="参数有误!")

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['project_id', 'ids'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_INTEGER),
                                  description="待删除待数据类型 id列表"),
        },
    ))
    def post(self, request):
        """
        删除(禁用)数据类型
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        try:
            pro_data = Project.objects.get(id=data["project_id"])
            if not request.user.is_superuser and pro_data.user.is_superuser:
                return JsonResponse(code="999983", msg="无操作权限！")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在!")
        pro_data = ProjectListSerializer(pro_data)
        if not pro_data.data["status"]:
            return JsonResponse(code="999985", msg="该项目已禁用")
        # 根据项目id和模块 id查找，若存在则删除
        try:
            for j in data["ids"]:
                obj = ApiDataType.objects.get(id=j, project=data["project_id"])
                if obj:
                    # obj.delete()  # 删除
                    obj.status = False
                    obj.save()
                    record_dynamic(project=data["project_id"], _type="禁用", operationObject="数据类型", user=request.user.pk,
                                   data="禁用数据类型列表“%s”" % obj.type)
            return JsonResponse(code="999999", msg="成功！")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="数据类型不存在！")


class DataStructure(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @swagger_auto_schema(manual_parameters=[
        openapi.Parameter(name="project_id", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER, description="项目id"),
        openapi.Parameter(name="type_id", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER, description="复杂数据类型id"),
        openapi.Parameter(name="name", in_=openapi.IN_QUERY, type=openapi.TYPE_STRING, description="参数名称"),
    ])
    def get(self, request):
        """
        获取复杂数据类型的组成
        """
        project_id = request.GET.get("project_id")
        type_id = request.GET.get("type_id")
        name = request.GET.get("name")
        # 校验参数
        if not project_id or not project_id.isdecimal():
            return JsonResponse(code="999996", msg="参数有误!")
        # 验证项目是否存在
        try:
            pro_data = Project.objects.get(id=project_id)
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在!")
        # 序列化结果
        pro_data = ProjectListSerializer(pro_data)
        # 校验项目状态
        if not pro_data.data["status"]:
            return JsonResponse(code="999985", msg="该项目已禁用")

        if type_id and not type_id.isdecimal():
            return JsonResponse(code="999996", msg="参数有误!")
        # 验证type_id是否存在
        try:
            if type_id:
                type_data = ApiDataType.objects.get(project=project_id, id=type_id)
                type_data = ApiDataTypeSerializer(type_data)
                if not type_data.data["status"]:
                    return JsonResponse(code="999985", msg="该类型已禁用")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="类型不存在!")

        # 查找项目下所有复杂数据类型结构，序列化结果
        obi = ApiDataStructure.objects.filter(status=True)
        if type_id:
            obi = obi.filter(type=type_id)
        if name:
            obi = obi.filter(name=name)
        obi = obi.order_by("id")
        serialize = ApiDataStructureSerializer(obi, many=True)
        return JsonResponse(data=serialize.data, code="999999", msg="成功!")


class AddDataStructure(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    def parameter_check(self, data):
        """
        校验参数
        """
        try:
            # 校验type类型为int
            if not data.get("project_id") or not isinstance(data["project_id"], int):
                return JsonResponse(code="999996", msg="参数有误!")
            if not data.get("type_id") or not isinstance(data["type_id"], int):
                return JsonResponse(code="999996", msg="参数有误!")
            if not data.get("type_sub_id") or not isinstance(data["type_sub_id"], int):
                return JsonResponse(code="999996", msg="参数有误!")
            if data["type_sub_id"] == data["type_id"]:  # 死循环啦 type_sub_id的类型也不能=子结构包含type_sub_id的复杂类型id
                return JsonResponse(code="999996", msg="参数有误!")
        except KeyError:
            return JsonResponse(code="999996", msg="参数有误!")

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['type_id', 'name', 'type_sub_id'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'type_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="复杂数据类型id"),
            'name': openapi.Schema(type=openapi.TYPE_STRING, description="子参数名"),
            'type_sub_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="子类型id"),
            'repeated': openapi.Schema(type=openapi.TYPE_INTEGER, description="是否为list"),
            'description': openapi.Schema(type=openapi.TYPE_STRING, description="子类型描述")
        },
    ))
    def post(self, request):
        """
        新增复杂类型的子参数
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        # 校验复杂类型状态
        try:
            pro_data = Project.objects.get(id=data["project_id"])
            if not request.user.is_superuser and pro_data.user.is_superuser:
                return JsonResponse(code="999983", msg="无操作权限！")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在!")
        pro_data = ProjectListSerializer(pro_data)
        if not pro_data.data["status"]:
            return JsonResponse(code="999985", msg="该项目已禁用")
        try:
            obj = ApiDataType.objects.get(id=data["type_id"], project=data["project_id"])
            obk = ApiDataType.objects.get(id=data["type_sub_id"], project=data["project_id"])
            type_data = ApiDataTypeSerializer(obj)
            type_sub_data = ApiDataTypeSerializer(obk)
            if not type_data.data["status"] or not type_sub_data.data["status"]:
                return JsonResponse(code="999985", msg="类型已禁用")
            if not type_data.data["complex"]:
                return JsonResponse(code="999986", msg="该类型不是复杂类型")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="类型不存在!")
        obi = ApiDataStructure.objects.filter(type=data["type_id"], name=data["name"])
        if obi:
            return JsonResponse(code="999997", msg="存在相同参数名称！")
        else:
            # 反序列化
            serializer = ApiDataStructureDeserializer(data=data)
            # 校验反序列化正确，正确则保存
            if serializer.is_valid():
                serializer.save(type=obj, type_sub=obk)
            else:
                print(serializer.errors)
                return JsonResponse(code="999998", msg="失败!")
            # 新增操作
            record_dynamic(project=data["project_id"],
                           _type="添加", operationObject="数据类型", user=request.user.pk,
                           data="新增复杂类型“%s”的子参数“%s”" % (obj.type, data["name"]))
            return JsonResponse(data={
                "type_id": serializer.data.get("id")
            }, code="999999", msg="成功!")


class UpdateDataStructure(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    def parameter_check(self, data):
        """
        校验参数
        """
        try:
            # 必传参数
            if not data.get("project_id") or not data.get("type_id") or not data.get("type_sub_id") \
                    or not data.get("id"):
                return JsonResponse(code="999996", msg="参数有误!")
            # 校验project_id, id类型为int
            if not isinstance(data["project_id"], int) or not isinstance(data["id"], int) or\
                    not isinstance(data["type_id"], int) or not isinstance(data["type_sub_id"], int):
                return JsonResponse(code="999996", msg="参数有误!")
            if data["type_id"] == data["type_sub_id"]:
                return JsonResponse(code="999996", msg="参数有误!")
        except KeyError:
            return JsonResponse(code="999996", msg="参数有误!")

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['type', 'name', 'type_sub'],
        properties={
            'id': openapi.Schema(type=openapi.TYPE_INTEGER, description="数据子类型id"),
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'type_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="复杂数据类型"),
            'name': openapi.Schema(type=openapi.TYPE_STRING, description="子类型参数名"),
            'type_sub_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="子类型"),
            'repeated': openapi.Schema(type=openapi.TYPE_INTEGER, description="是否为list"),
            'description': openapi.Schema(type=openapi.TYPE_STRING, description="子类型描述")
        },
    ))
    def post(self, request):
        """
        修改数据子类型
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        try:
            pro_data = Project.objects.get(id=data["project_id"])
            if not request.user.is_superuser and pro_data.user.is_superuser:
                return JsonResponse(code="999983", msg="无操作权限！")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在!")
        pro_data = ProjectListSerializer(pro_data)
        if not pro_data.data["status"]:
            return JsonResponse(code="999985", msg="该项目已禁用")
        try:
            obj = ApiDataType.objects.get(id=data["type_id"], project=data["project_id"])
            obk = ApiDataType.objects.get(id=data["type_sub_id"], project=data["project_id"])
            type_data = ApiDataTypeSerializer(obj)
            type_sub_data = ApiDataTypeSerializer(obk)
            if not type_data.data["status"] or not type_sub_data.data["status"]:
                return JsonResponse(code="999985", msg="类型已禁用")
            if not type_data.data["complex"]:
                return JsonResponse(code="999986", msg="该类型不是复杂类型")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="类型不存在!")

        try:
            obk = ApiDataStructure.objects.get(id=data["id"], type_id=data["type_id"])
        except ObjectDoesNotExist:
            return JsonResponse(code="999991", msg="id不存在!")

        # obk.delete()

        # 反序列化
        serializer = ApiDataStructureDeserializer(data=data)
        # 校验反序列化正确，正确则保存
        if serializer.is_valid():
            # serializer.save(id=data["id"])
            serializer.update(instance=obk, validated_data=data)
        else:
            print(serializer.errors)
            return JsonResponse(code="999998", msg="失败!")
        record_dynamic(project=data.get("project_id"),
                       _type="修改", operationObject="数据子类型", user=request.user.pk,
                       data="修改复杂类型“%s”的子参数“%s”" % (type_data.data["type"], data["name"]))
        return JsonResponse(code="999999", msg="成功!")


class DelDataStructure(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    def parameter_check(self, data):
        """
        校验参数
        """
        try:
            if not data.get("ids") or not data.get("project_id") or not data.get("type_id"):
                return JsonResponse(code="999995", msg="参数有误！")
            # 校验project_id, id类型为int
            if not isinstance(data["ids"], list) or not isinstance(data["project_id"], int)\
                    or not isinstance(data["type_id"], int):
                for i in data["ids"]:
                    if not isinstance(i, int) or not isinstance(int(i), int):
                        return JsonResponse(code="999995", msg="参数有误！")
                return JsonResponse(code="999995", msg="参数有误！")
        except KeyError:
            return JsonResponse(code="999996", msg="参数有误!")

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['project_id', 'ids'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'type_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="复杂类型id"),
            'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_INTEGER),
                                  description="待删除待数据子类型 id列表"),
        },
    ))
    # TODO 目前只支持批量删除同一个复杂类型的子结构
    def post(self, request):
        """
        删除(禁用)数据类型
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        try:
            pro_data = Project.objects.get(id=data["project_id"])
            if not request.user.is_superuser and pro_data.user.is_superuser:
                return JsonResponse(code="999983", msg="无操作权限！")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="项目不存在!")
        pro_data = ProjectListSerializer(pro_data)
        if not pro_data.data["status"]:
            return JsonResponse(code="999985", msg="该项目已禁用")
        try:
            type_data = ApiDataType.objects.get(id=data["type_id"], project=data["project_id"])
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="复杂数据类型不存在!")
        type_data = ApiDataTypeSerializer(type_data)
        if not type_data.data["status"]:
            return JsonResponse(code="999985", msg="复杂数据类型已禁用")

        # 根据项目id和模块 id查找，若存在则删除
        try:
            for j in data["ids"]:
                obj = ApiDataStructure.objects.get(id=j, type=data["type_id"])
                if obj:
                    # obj.delete()  # 删除
                    obj.status = False
                    obj.save()
                    record_dynamic(project=data["project_id"], _type="禁用", operationObject="子数据类型", user=request.user.pk,
                                   data="禁用复杂类型“%s”的子参数“%s”" % (type_data.data["type"], obj.name))
            return JsonResponse(code="999999", msg="成功！")
        except ObjectDoesNotExist:
            return JsonResponse(code="999995", msg="子类型不存在！")
